<script setup>
import { getKlineHistory } from '@/api/common/kline.js'
import Datafees from '@/config/kline/datafees.js'
import { getConfig, getConfiga, getIntervalList, getStudyList } from '@/config/kline/index.js'
import { _coinWebSocket } from '@/plugin/socket/index'
import { _t18, _klineTimeFormat } from '@/utils/public'
import { socketDict } from '@/config/dict'
import PubSub from 'pubsub-js'
import { _add, _div, _mul, priceFormat } from '@/utils/decimal'
import _ from 'lodash'
import { ref, reactive, computed, onMounted, onBeforeUnmount, nextTick } from 'vue' // ✅ 补全导入
import { useMainStore } from '@/store'
import { useTradeStore } from '@/store/trade'
import { debounce, throttle } from 'lodash'

const props = defineProps({
  type: { type: String, default: 'detail' },
  coinInfo: { type: Object, default: () => ({}) }
})
console.log(props.coinInfo)
/** 分辨率(k线图右侧刻度) */
const priceScale = computed(() => {
  let tempPricescale = 10000
  const v = props.coinInfo?.amount
  if (v > 100) tempPricescale = 100
  else if (v < 0.1) tempPricescale = 1000000
  else if (v < 10) tempPricescale = 100000
  return tempPricescale
})

/** 临时交易(打开页面币种初始信息) */
const tempTrade = {
  time: '',
  amount: '',
  open: '',
  high: '',
  low: '',
  close: '',
  volume: '',
  lastClose: '',
  intervention: false
}
/** k线显示样式 */
const klineStyle = ref(true)
/** 分辨率差 */
const intervalDiff = ref('')
/** 总分辨率列表 */
const intervalList = getIntervalList()
/** 指标列表 */
const studyList = getStudyList()
const headIntervalList = reactive([])
const menuIntervalList = intervalList.filter((elem) => elem?.isMore)

/** K线使用 分辨率列表 */
let supportedResolutions = []
/** 数据sdk实例 */
let datafeeds = null
/** 指标 */
let studies = reactive([])
/** 当前symbol、interval 过渡对象 */
let currentCoinInfo = reactive({})
let currentInterval = reactive({})

/** KLine */
const klineId = computed(() => `kline_${props.type}`)
let widget = null
const mainStore = useMainStore()
const tradeStore = useTradeStore()

/** 交易对监听 */
const eventTradeSymbolChange = debounce((e) => {
  const symbol = e.detail.symbol
  const tempCoinInfo = e.detail.coinInfo
  console.log(tempCoinInfo)
  // 分辨率改变
  const tempHeadIntervalList = getHeadIntervalList(tempCoinInfo)
  if (
    tempHeadIntervalList.map((elem) => elem.value).join() !==
    headIntervalList.map((elem) => elem.value).join()
  ) {
    supportedResolutions = getSupportedResolutions(tempCoinInfo)
    headIntervalList.splice(0, headIntervalList.length, ...tempHeadIntervalList)
    Object.assign(currentInterval, headIntervalList[0] || {})
  }

  showMenu.value = false

  // ✅ 切币种只 setSymbol，不重新 initWidget（避免反复创建图表）
  setSymbol(symbol, currentInterval.interval, () => {
    Object.assign(currentCoinInfo, tempCoinInfo) // ✅ 用事件里的 coinInfo
  })
}, 200)

/** 获取分辨率 */
const getSupportedResolutions = (tempCoinInfo = currentCoinInfo) => {
  let tempList = intervalList.map((elem) => elem.interval)
  if (tempCoinInfo?.market === 'mt5') {
    tempList = intervalList.filter((elem) => elem.market === 'mt5').map((elem) => elem.interval)
  }
  return tempList
}

/** 获取分辨率显示菜单 */
const getHeadIntervalList = (tempCoinInfo = currentCoinInfo) => {
  let tempList = intervalList.filter((elem) => !elem?.isMore)
  if (tempCoinInfo?.market === 'mt5' || tempCoinInfo?.coinType === 3) {
    tempList = intervalList.filter((elem) => elem.market === 'mt5')
  }
  return tempList
}

watch(
  () => props.coinInfo,
  (newVal, oldVal) => {
    // 忽略空值或 symbol 相同的情况
    if (!newVal || newVal.symbol === oldVal?.symbol) return

    console.log('🔄 检测到 coinInfo 变化:', newVal.symbol)

    // 清除旧的图表实例
    widget?.remove?.()
    unsubscribeTrades(true)

    // 更新当前币种信息
    Object.assign(currentCoinInfo, newVal)
    supportedResolutions = getSupportedResolutions(newVal)
    headIntervalList.splice(0, headIntervalList.length, ...getHeadIntervalList(newVal))
    Object.assign(currentInterval, headIntervalList[0] || {})

    nextTick(() => initWidget()) // 重新初始化图表
  },
  { deep: true }
)

onMounted(async () => {
  Object.assign(currentCoinInfo, props.coinInfo)
  supportedResolutions = getSupportedResolutions()
  headIntervalList.splice(0, headIntervalList.length, ...getHeadIntervalList())
  Object.assign(currentInterval, headIntervalList[0] || {})
  document.addEventListener('event_tradeSymbolChange', eventTradeSymbolChange)
  await nextTick()
  initWidget()
})

onBeforeUnmount(() => {
  document.removeEventListener('event_tradeSymbolChange', eventTradeSymbolChange)
  unsubscribeTrades(true)
  widget?.remove() // ✅ 守卫
})

/** 设置币种、周期 */
const setSymbol = async (symbol, interval, callBack) => {
  if (currentCoinInfo.symbol !== symbol || interval !== currentInterval.interval) {
    widget?.setSymbol(symbol, interval, () => {
      // console.log('------setSymbol---------', symbol, interval)
      Object.assign(
        currentInterval,
        intervalList.find((elem) => elem.interval === interval) || {}
      )
      callBack && callBack()
    })
  }
}

// 数据实例
const dataFeedInstance = {}

/** 获取配置 */
dataFeedInstance.getConfig = async (callback) => {
  setTimeout(() => {
    callback({
      supported_resolutions: supportedResolutions,
      supports_marks: false,
      supports_timescale_marks: true,
      supports_time: true
    })
  }, 0)
}

/** 获取服务器时间 */
dataFeedInstance.getServerTime = async (callback) => {
  const time = Date.now()
  callback && callback(time)
}

const parseTimestamp = (ts) => {
  if (!ts && ts !== 0) return null
  let num = Number(ts)
  if (Number.isNaN(num)) return null
  if (num < 1e11) num = num * 1000 // 秒->毫秒
  return num
}

/** 获取历史KLine数据 */
dataFeedInstance.getBars = async ({ symbolInfo: coinInfo, resolution, from, firstDataRequest }) => {
  const tempInterval = intervalList.find((elem) => elem.interval === resolution)
  try {
    if (tempInterval && (from === '' || from > 0)) {
      const params = {
        symbol: coinInfo.market === 'metal' ? coinInfo.symbol : coinInfo.coinUpperCase,
        interval: tempInterval.key,
        limit: 1000
      }
      if (from) params.end = from

      const { data } = await getKlineHistory({
        ...params,
        interval: tempInterval.key,
        symbol: coinInfo.market === 'metal' ? coinInfo.symbol : coinInfo.coinUpperCase,
        market: coinInfo.market
      })

      let barList = []
      if (data) {
        tradeStore.setKlineTicker(data.ticker)
        barList = data.historyKline || []
      }

      barList = barList
        .map((elem) => ({
          open: parseFloat(elem.o),
          high: parseFloat(elem.h),
          low: parseFloat(elem.l),
          close: parseFloat(priceFormat(elem.c)),
          amount: parseFloat(priceFormat(elem.c)),
          volume: parseFloat(elem.v),
          time: parseTimestamp(elem.T)
        }))
        .filter((b) => b.time) // ✅ 过滤无效时间
        .sort((a, b) => a.time - b.time)

      if (firstDataRequest && barList.length) {
        const last = barList[barList.length - 1]
        Object.assign(tempTrade, {
          amount: last.amount,
          open: last.open,
          close: last.close,
          high: last.high,
          low: last.low,
          volume: last.volume,
          time: last.time,
          lastClose: last.close,
          intervention: false
        })

        // ✅ 计算分辨率差的兜底
        if (barList.length >= 2) {
          intervalDiff.value = Math.abs(last.time - barList[barList.length - 2].time)
        } else {
          // 尝试用预设映射或默认 60s
          intervalDiff.value = (tempInterval.ms ?? 60000)
        }

        updateDataKline(tempTrade)
        subscribeTrades({
          coin: coinInfo.coin,
          symbol: coinInfo.symbol,
          interval: tempInterval.key,
          firstDataRequest
        })
      }
      return barList
    }
  } catch (error) {
    unsubscribeTrades(true)
    return []
  }
  return []
}

/** 加载商品配置 */
dataFeedInstance.resolveSymbol = async () => {
  return {
    name: props.coinInfo.symbolUpperCase,
    coin: props.coinInfo.coin,
    coinUpperCase: props.coinInfo.coin,
    symbol: props.coinInfo.symbol,
    symbolUpperCase: props.coinInfo.symbolUpperCase,
    market: props.coinInfo.market,
    fractional: false,
    session: '24x7',
    has_intraday: true,
    has_weekly_and_monthly: true,
    exchange: __config._APP_EXCHANGE_NAME,
    description: props.coinInfo.symbolUpperCase,
    pricescale: priceScale.value,
    minmov: 1,
    supported_resolutions: supportedResolutions
  }
}

/** 初始化图表 */
const initWidget = () => {
  // ✅ 重建前先移除旧实例
  widget?.remove()

  datafeeds = new Datafees(dataFeedInstance)
  const theme = window.__theme
  const configFunction = klineStyle.value ? getConfiga : getConfig

  widget = new TradingView.widget({
    symbol: props.coinInfo.symbolUpperCase,
    theme,
    debug: false,
    autosize: true,
    interval: currentInterval.interval,
    container_id: klineId.value,
    datafeed: datafeeds,
    library_path: '/charting_library/',
    custom_css_url: `../tradingview_${theme}.css`,
    locale: 'en',
    timezone: mainStore.timezone,
    customFormatters: {
      dateFormatter: { format(date) { return _klineTimeFormat(date.getTime(), 'DD/MM/YYYY', true) } },
      timeFormatter: { format(date) { return _klineTimeFormat(date.getTime(), 'HH:mm:ss', true) } }
    },
    preset: 'mobile',
    ...configFunction(theme)
  })

  widget.onChartReady(() => {
    createStudy()
  })
}

/** 创建指标 */
const createStudy = () => {
  const id = setStudy(studyList[0].name)
  studies.push(id)
}

const changeStyle = () => {
  klineStyle.value = !klineStyle.value
  initWidget() // ✅ 切换样式时重建，但先 remove
}

/** 订阅客户端列表 */
const subscribeClientList = []

/** 取消订阅 */
const unsubscribeTrades = (firstDataRequest = false) => {
  if (!currentCoinInfo.coin) return
  try {
    _coinWebSocket?.send?.({
      op: socketDict.unsubscribe,
      type: socketDict.KLINE,
      symbol: currentCoinInfo.coin,
      interval: currentInterval.key
    })
    if (firstDataRequest) {
      subscribeClientList.forEach((subKey) => subKey && PubSub.unsubscribe(subKey))
      subscribeClientList.length = 0
      _coinWebSocket?.send?.({
        op: socketDict.unsubscribe,
        type: socketDict.TRADE,
        symbol: currentCoinInfo.coin
      })
    }
  } catch (e) {
    // 忽略 ws 未连接等异常
  }
}

/** 订阅实时成交/K线 */
const subscribeTrades = async (params) => {
  // 先取消订阅
  unsubscribeTrades(params.firstDataRequest)

  _coinWebSocket?.send?.({
    op: socketDict.subscribe,
    type: socketDict.KLINE,
    symbol: params.coin,
    interval: params.interval
  })

  if (params.firstDataRequest) {
    _coinWebSocket?.send?.({
      op: socketDict.subscribe,
      type: socketDict.TRADE,
      symbol: params.coin
    })
  }

  const candlestickKey = PubSub.subscribe(socketDict.KLINE, (key, data) => {
    const tempData = data?.data?.tick
    if (!tempData || data.symbol !== params.coin) return

    if (tempTrade.intervention !== tempData?.intervention) {
      tempData.open = tempTrade.lastClose
      tempTrade.intervention = tempData?.intervention
    }

    // ✅ 使用 intervalDiff 做对齐，兜底保证为数字
    const diff = Number(intervalDiff.value) || 60000
    const tempTime = Math.floor((tempData.id || 0) / diff) * diff

    if (!tempTrade.time || tempTrade.time < tempTime) {
      tempTrade.time = tempTime
      tempTrade.open = tempData.open
    }
    tempTrade.high = tempData.high
    tempTrade.low = tempData.low
    tempTrade.close = Number(priceFormat(tempData.close))
    tempTrade.volume = tempData.vol
    updateDataKline(tempTrade)
  })
  subscribeClientList.push(candlestickKey)
}

/** 更新数据 */
const updateDataKline = (newData) => {
  const syncTicker = () => {
    const now = Date.now()
    tradeStore.klineTicker = {
      ...tradeStore.klineTicker,
      closePrice: newData.close,
      highPrice: Math.max(newData.high, tradeStore.klineTicker?.highPrice || 0),
      lowPrice: Math.min(newData.low, tradeStore.klineTicker?.lowPrice ?? newData.low ?? Infinity),
      openPrice: newData.open,
      lastUpdate: now
    }
    PubSub.publish('KLINE_DATA_SYNC', {
      close: newData.close,
      high: newData.high,
      low: newData.low,
      open: newData.open,
      volume: newData.volume,
      T: now,
      symbol: currentCoinInfo.coin,
      isMaster: true
    })
  }

  syncTicker()

  if (newData?.close != null) {
    datafeeds.updateData(newData)
    PubSub.publish(socketDict.DETAIL, {
      data: { ...newData, vol: newData.volume },
      origin: 'kline',
      symbol: currentCoinInfo.coin,
      type: socketDict.DETAIL
    })
  }
}

/** 更新数据 限流 */
const updateDataKlineThrottle = throttle(function (newData) {
  updateDataKline(newData)
}, 300)

/** 显示更多分辨率 */
const showMenu = ref(false)

/** 选中分辨率 */
const checkedInterval = (item, type = '') => {
  if (item.interval !== currentInterval.interval) {
    setSymbol(props.coinInfo.symbol, item.interval)
  }
  showMenu.value = !!type
}

// 指标选择
const currentStudy = ref('')

/** 设置指标 */
const setStudy = (name) => {
  if (currentStudy.value === name) return
  const activeChart = widget.activeChart()
  // 关闭旧指标
  if (currentStudy.value) {
    const oldStudy = studyList.find((elem) => elem.name === currentStudy.value)
    oldStudy?.list?.forEach((id) => {
      try { activeChart.removeEntity(id) } catch (e) {}
    })
  }
  // 设置新指标
  currentStudy.value = name
  const newStudy = studyList.find((elem) => elem.name === currentStudy.value)
  const tempList = []
  newStudy.cycleList.forEach(async (cycle, index) => {
    let result = ''
    if (name === 'MACD' || name === 'Bollinger Bands') {
      result = await activeChart.createStudy(currentStudy.value, false, false, [], {})
    } else {
      result = await activeChart.createStudy(currentStudy.value, false, false, [cycle], {
        'plot.color': newStudy.colorList[index],
        'plot.linewidth': 2
      })
    }
    tempList.push(result)
  })
  newStudy.list = tempList
}
</script>

<template>
  <div>
    <div class="third">
      <div class="list">
        <div class="thirdLeft">
          <div
            :class="{
              'hightItem item ff-num': item.interval === currentInterval.interval,
              'item ff-num': true
            }"
            v-for="(item, index) in headIntervalList"
            :key="index"
            @click="checkedInterval(item)"
          >
            {{ item.value }}
          </div>
          <div @click="changeStyle" style="margin-left:20px;">
            <img src="/static/img/icon_line.svg" alt="" />
          </div>
        </div>
        <!-- 更多开关（如需） -->
        <!--
        <div class="thirdRight" v-show="currentCoinInfo.market != 'mt5'" @click="showMenu = !showMenu">
          <div>{{ _t18(`exchange_more`) }}</div>
          <svg-load v-if="!showMenu" name="jiantou-x" class="thirdRightImg"></svg-load>
          <svg-load v-if="showMenu" name="jiantou-s" class="thirdRightImg"></svg-load>
        </div>
        -->
      </div>
    </div>

    <div
      class="selectTimes"
      v-if="showMenu"
      @touchmove.prevent
      @mousewheel.prevent
      @click="showMenu = false"
    >
      <div class="times">
        <div
          v-for="(item, index) in menuIntervalList"
          :key="index"
          :class="{ hightItem: item.interval === currentInterval.interval, 'item ff-num': true }"
          @click="checkedInterval(item, 'menu')"
        >
          {{ item.value }}
        </div>
      </div>
    </div>
  </div>

  <div :id="klineId" class="candlestick"></div>

  <div class="studyList">
    <div
      :class="item.name === currentStudy ? 'hightItem studyItem' : 'studyItem'"
      v-for="(item, index) in studyList"
      :key="index"
      @click="setStudy(item.name)"
    >
      {{ item.label }}
    </div>
  </div>
</template>

<style lang="scss" scoped>
.candlestick {
  height: 348px;
  background-color: var(--ex-candlestick-bg);
}
.hightItem {
  color: #17ac74 !important;
}
.third {
  margin-top: 10px;
  padding: 0px 15px 10px;
  border-bottom: 1px solid var(--ex-border-color);
  .list {
    background-color: #000;
    display: flex;
    justify-content: space-between;
    align-items: center;
    .thirdLeft {
      flex: 1;
      background-color: var(--ex-default-background-color);
      display: flex;
      font-size: 14px;
      color: var(--ex-default-font-color);
      .item {
        flex: 1;
        margin-right: 20px;
        &:last-child {
          margin-right: 0;
        }
      }
    }
    .thirdRight {
      display: flex;
      align-items: center;
      font-size: 14px;
      color: var(--ex-font-color9);
      .thirdRightImg {
        width: 10px;
        height: 6px;
        margin-left: 5px;
      }
    }
  }
}
.selectTimes {
  position: absolute;
  height: 100vh;
  width: var(--ex-max-width);
  background: rgba(#000000, 0.6);
  z-index: 10;
  .times {
    background-color: var(--ex-default-background-color);
    position: absolute;
    width: 100%;
    height: 84px;
    display: flex;
    align-items: center;
    border-radius: 0 0 15px 15px;
    .item {
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0 15px;
      width: 37px;
      height: 23px;
      background: var(--ex-div-bgColor12);
      border-radius: 2px;
      font-size: 12px;
      color: var(--ex-default-font-color);
    }
  }
}
.studyList {
  display: flex;
  padding: 10px 15px;
  .studyItem {
    font-size: 14px;
    color: var(--ex-default-font-color);
    margin-right: 30px;
  }
}
</style>
